package com.beauty.inventory.service.impl;

import com.beauty.inventory.service.DistributedLockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Service
@RequiredArgsConstructor
@Slf4j
public class RedissonDistributedLockServiceImpl implements DistributedLockService {

    private final RedissonClient redissonClient;
    
    private static final long DEFAULT_WAIT_TIME = 10;
    private static final long DEFAULT_LEASE_TIME = 30;
    private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;

    @Override
    public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime, 
                             TimeUnit timeUnit, Supplier<T> supplier) throws InterruptedException {
        String config = "无法获取配置";
        try {
            config = redissonClient.getConfig().toJSON();
        } catch (IOException e) {
            log.error("【Redisson分布式锁】获取配置信息异常", e);
        }
        log.info("【Redisson分布式锁】初始化锁对象，Redisson客户端配置：{}", config);
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;
        
        try {
            log.info("【Redisson分布式锁】尝试获取锁，lockKey: {}, waitTime: {}秒, leaseTime: {}秒, 线程: {}", 
                    lockKey, waitTime, leaseTime, Thread.currentThread().getName());
            
            locked = lock.tryLock(waitTime, leaseTime, timeUnit);
            
            if (locked) {
                log.info("【Redisson分布式锁】成功获取锁，lockKey: {}, 线程: {}, 锁TTL: {}ms", 
                        lockKey, Thread.currentThread().getName(), lock.remainTimeToLive());
                T result = supplier.get();
                log.info("【Redisson分布式锁】锁内业务执行完成，lockKey: {}, 剩余TTL: {}ms", 
                        lockKey, lock.remainTimeToLive());
                return result;
            } else {
                log.warn("【Redisson分布式锁】获取锁超时，lockKey: {}, 线程: {}, 锁状态: 已锁定={}, 当前线程持有={}", 
                        lockKey, Thread.currentThread().getName(), lock.isLocked(), lock.isHeldByCurrentThread());
                throw new RuntimeException("获取分布式锁超时，lockKey: " + lockKey);
            }
        } catch (Exception e) {
            log.error("【Redisson分布式锁】执行锁内业务异常，lockKey: {}, 异常: {}", lockKey, e.getMessage(), e);
            throw e;
        } finally {
            if (locked) {
                lock.unlock();
                log.info("【Redisson分布式锁】释放锁，lockKey: {}, 线程: {}, 锁状态: 已锁定={}", 
                        lockKey, Thread.currentThread().getName(), lock.isLocked());
            }
        }
    }

    @Override
    public <T> T executeWithLock(String lockKey, Supplier<T> supplier) throws InterruptedException {
        return executeWithLock(lockKey, DEFAULT_WAIT_TIME, DEFAULT_LEASE_TIME, DEFAULT_TIME_UNIT, supplier);
    }

    @Override
    public boolean tryLock(String lockKey, long leaseTime, TimeUnit timeUnit) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            log.info("【分布式锁】尝试获取锁（不等待），lockKey: {}, leaseTime: {}秒", 
                    lockKey, leaseTime);
            boolean locked = lock.tryLock(0, leaseTime, timeUnit);
            
            if (locked) {
                log.info("【分布式锁】成功获取锁，lockKey: {}", lockKey);
            } else {
                log.warn("【分布式锁】获取锁失败，lockKey: {}", lockKey);
            }
            
            return locked;
        } catch (InterruptedException e) {
            log.error("【分布式锁】获取锁过程被中断，lockKey: {}", lockKey, e);
            Thread.currentThread().interrupt();
            return false;
        }
    }

    @Override
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
            log.info("【分布式锁】释放锁，lockKey: {}", lockKey);
        } else {
            log.warn("【分布式锁】当前线程未持有锁，不能释放，lockKey: {}", lockKey);
        }
    }
} 